package ch.il07.converter.persistance.tests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import org.junit.Before;
import org.junit.Test;

import ch.il07.converter.persistence.Persistence;
import ch.il07.converter.persistence.PersistenceHelper;
import ch.il07.converter.persistence.entities.AccessLevel;
import ch.il07.converter.persistence.entities.Measurand;
import ch.il07.converter.persistence.entities.Unit;
import ch.il07.converter.persistence.entities.User;
import ch.il07.converter.persistence.exceptions.AlreadyDefinedException;
import ch.il07.converter.persistence.exceptions.NoSuchUserException;
import ch.il07.converter.persistence.exceptions.PersistenceException;
import ch.il07.converter.persistence.exceptions.UpdateException;
import ch.il07.converter.persistence.exceptions.UserAlreadyExistsException;
import ch.il07.utils.RandomHelper;

public class UpdateAnythingTest {

	private Persistence persistence;

	@Before
	public void setUp() throws PersistenceException {
		persistence = PersistenceHelper.getPersistence();
	}

	@Test
	public void updateUser() throws UserAlreadyExistsException,
			PersistenceException {
		String username = RandomHelper.randString();
		persistence.addUser(username, RandomHelper.getEmail(username),
				username, AccessLevel.USER);
		User oldUser = persistence.getUser(username, username);

		String newUsername = RandomHelper.randString();
		String newPassword = RandomHelper.randString();
		String newEMail = RandomHelper.getEmail(newUsername);
		AccessLevel newAccessLevel = AccessLevel.ADMINISTRATOR;

		oldUser.setUsername(newUsername);
		oldUser.setPassword(newPassword);
		oldUser.setEmail(newEMail);
		oldUser.setAccessLevel(newAccessLevel);
		persistence.updateUser(oldUser);

		User updatedUser = persistence.getUser(newUsername, newPassword);
		assertNotNull("user has obviously not updated", updatedUser);
		assertEquals("accessLevel could not be changed", newAccessLevel,
				updatedUser.getAccessLevel());
		assertEquals("email could not be changed", newEMail,
				updatedUser.getEmail());
	}

	@Test
	public void updateMeasurandAndUnit() throws NoSuchUserException,
			AlreadyDefinedException, PersistenceException {
		String username = RandomHelper.randString();
		persistence.addUser(username, RandomHelper.getEmail(username), username, AccessLevel.USER);
		User user = persistence.getUser(username, username);
		assertNotNull("user could not be added to persistence", user);

		String measurandName = RandomHelper.randString();
		persistence.addMeasurand(new Measurand(measurandName, new Unit(
				RandomHelper.randString(), 1.0), user), user.getUsername());
		Measurand oldMeasurand = persistence.getMeasurand(measurandName, user.getUsername());
		assertNotNull("measurand could not be added to persistence", oldMeasurand);
		
		Unit unit2 = new Unit(RandomHelper.randString(), 1.23, 4.56, user);
		persistence.addUnit(oldMeasurand, unit2);
		
		String newMeasurandName = RandomHelper.randString();
		String newDescription = RandomHelper.randString(20);
		oldMeasurand.setName(newMeasurandName);
		oldMeasurand.setDescription(newDescription);
		
		// update name & description
		persistence.updateMeasurand(oldMeasurand);
		Measurand updatedMeasurand = persistence.getMeasurand(newMeasurandName, username);
		assertNotNull("measurand could not be updated", updatedMeasurand);
		assertEquals("description could not be updated", newDescription, updatedMeasurand.getDescription());
		
		Unit oldUnit = updatedMeasurand.getUnits().get(0);
		String newName = RandomHelper.randString();
		String newSymbol = RandomHelper.randString();
		Double newFactor = 7.89;
		Double newShift = 10.1112;
		oldUnit.setName(newName);
		oldUnit.setSymbol(newSymbol);
		oldUnit.setDivisor(newFactor);
		oldUnit.setShift(newShift);
		
		// update almost entire unit
		persistence.updateUnit(updatedMeasurand, oldUnit);
		Unit updatedUnit = persistence.getMeasurand(newMeasurandName, username).getUnits().get(0);
		assertNotNull("unit could not be updated", updatedUnit);
		assertEquals("unit name could not be updated", newName, updatedUnit.getName());
		assertEquals("unit symbol could not be updated", newSymbol, updatedUnit.getSymbol());
		assertEquals("", newFactor, updatedUnit.getDivisor());
		assertEquals("unit divisor could not be updated", newFactor, updatedUnit.getDivisor());
	
		// TODO testen, ob man diesen update methoden auch einen measurand oder eine unit public machen könnte
		// das heisst, die user ID auf null zu setzen
	}

	@Test(expected=UpdateException.class)
	public void updateDuplicateMeasurandName() throws PersistenceException {
		String measurandName = RandomHelper.randString();
		persistence.addMeasurand(new Measurand(measurandName, new Unit(
				RandomHelper.randString(), 1D)), null);

		String measurandName2 = RandomHelper.randString();
		persistence.addMeasurand(new Measurand(measurandName2, new Unit(
				RandomHelper.randString(), 1D)), null);
		Measurand measurand2 = persistence.getMeasurand(measurandName2, null);

		// now, try to update the name of the second measurand to the name of
		// the first measurand
		measurand2.setName(measurandName);

		persistence.updateMeasurand(measurand2);
	}
	
	@Test(expected=UpdateException.class)
	public void updateDuplicateUnitName() throws PersistenceException {
		String measurandName = RandomHelper.randString();
		String defaultUnitName = RandomHelper.randString();
		persistence.addMeasurand(new Measurand(measurandName, new Unit(
				defaultUnitName, 1D)), null);

		String unitName2 = RandomHelper.randString();
		persistence.addUnit(persistence.getMeasurand(measurandName, null), new Unit(unitName2, 2D));
		
		Measurand m = persistence.getMeasurand(measurandName, null);
		Unit unit = m.getUnits().get(0);

		// now, try to update the name of the second unit to the name of
		// the default unit
		unit.setName(defaultUnitName);

		persistence.updateUnit(m, unit);
	}
	
	@Test
	public void updateDuplicateUnitNameForDifferentMeasurand() throws PersistenceException {
		String measurandName1 = RandomHelper.randString();
		String unitName1 = RandomHelper.randString();
		persistence.addMeasurand(new Measurand(measurandName1, new Unit(
				unitName1, 1D)), null);
		
		String measurandName2 = RandomHelper.randString();
		String unitName2 = RandomHelper.randString();
		persistence.addMeasurand(new Measurand(measurandName2, new Unit(
				unitName2, 1D)), null);
		Measurand measurand2 = persistence.getMeasurand(measurandName2, null);
		
		// should be possible to set the name of the unit to the name of the unit of another measurand
		Unit defaultUnit2 = measurand2.getDefaultUnit();
		defaultUnit2.setName(unitName1);
		persistence.updateUnit(measurand2, defaultUnit2);
	}
}
